{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "_cell_guid": "b1076dfc-b9ad-4769-8c92-a6c4dae69d19",
    "_uuid": "8f2839f25d086af736a60e9eeb907d3b93b6e0e5",
    "execution": {
     "iopub.execute_input": "2020-12-28T12:05:28.026854Z",
     "iopub.status.busy": "2020-12-28T12:05:28.026116Z",
     "iopub.status.idle": "2020-12-28T12:05:55.581603Z",
     "shell.execute_reply": "2020-12-28T12:05:55.580582Z"
    },
    "papermill": {
     "duration": 27.580581,
     "end_time": "2020-12-28T12:05:55.581736",
     "exception": false,
     "start_time": "2020-12-28T12:05:28.001155",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: datatable in /opt/conda/lib/python3.7/site-packages (0.11.0)\r\n"
     ]
    }
   ],
   "source": [
    "!pip install datatable"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "_cell_guid": "79c7e3d0-c299-4dcb-8224-4455121ee9b0",
    "_uuid": "d629ff2d2480ee46fbb7e2d37f6b5fab8052498a",
    "execution": {
     "iopub.execute_input": "2020-12-28T12:05:55.626431Z",
     "iopub.status.busy": "2020-12-28T12:05:55.625779Z",
     "iopub.status.idle": "2020-12-28T12:05:58.097521Z",
     "shell.execute_reply": "2020-12-28T12:05:58.096660Z"
    },
    "papermill": {
     "duration": 2.49588,
     "end_time": "2020-12-28T12:05:58.097632",
     "exception": false,
     "start_time": "2020-12-28T12:05:55.601752",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style type='text/css'>\n",
       ".datatable table.frame { margin-bottom: 0; }\n",
       ".datatable table.frame thead { border-bottom: none; }\n",
       ".datatable table.frame tr.coltypes td {  color: #FFFFFF;  line-height: 6px;  padding: 0 0.5em;}\n",
       ".datatable .bool    { background: #DDDD99; }\n",
       ".datatable .object  { background: #565656; }\n",
       ".datatable .int     { background: #5D9E5D; }\n",
       ".datatable .float   { background: #4040CC; }\n",
       ".datatable .str     { background: #CC4040; }\n",
       ".datatable .row_index {  background: var(--jp-border-color3);  border-right: 1px solid var(--jp-border-color0);  color: var(--jp-ui-font-color3);  font-size: 9px;}\n",
       ".datatable .frame tr.coltypes .row_index {  background: var(--jp-border-color0);}\n",
       ".datatable th:nth-child(2) { padding-left: 12px; }\n",
       ".datatable .hellipsis {  color: var(--jp-cell-editor-border-color);}\n",
       ".datatable .vellipsis {  background: var(--jp-layout-color0);  color: var(--jp-cell-editor-border-color);}\n",
       ".datatable .na {  color: var(--jp-cell-editor-border-color);  font-size: 80%;}\n",
       ".datatable .footer { font-size: 9px; }\n",
       ".datatable .frame_dimensions {  background: var(--jp-border-color3);  border-top: 1px solid var(--jp-border-color0);  color: var(--jp-ui-font-color3);  display: inline-block;  opacity: 0.6;  padding: 1px 10px 1px 5px;}\n",
       ".datatable .frame thead tr.colnames {  background-image: url('');  background-repeat: repeat-x;  background-size: 14px;  height: 28px;}\n",
       "</style>\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "{'divide': 'warn', 'over': 'warn', 'under': 'ignore', 'invalid': 'warn'}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from collections import defaultdict\n",
    "import datatable as dt\n",
    "import lightgbm as lgb\n",
    "from matplotlib import pyplot as plt\n",
    "import riiideducation\n",
    "import torch\n",
    "\n",
    "\n",
    "# Error handling, ignore all\n",
    "np.seterr(divide = 'ignore', invalid = 'ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:05:58.141030Z",
     "iopub.status.busy": "2020-12-28T12:05:58.140466Z",
     "iopub.status.idle": "2020-12-28T12:05:58.144295Z",
     "shell.execute_reply": "2020-12-28T12:05:58.143714Z"
    },
    "papermill": {
     "duration": 0.027002,
     "end_time": "2020-12-28T12:05:58.144393",
     "exception": false,
     "start_time": "2020-12-28T12:05:58.117391",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "data_types_dict = {\n",
    "    'user_id': 'int32', \n",
    "    'timestamp': 'int64',\n",
    "    'content_id': 'int16', \n",
    "    'answered_correctly': 'int8', \n",
    "    'prior_question_elapsed_time': 'float32', \n",
    "    'prior_question_had_explanation': 'bool'\n",
    "}\n",
    "\n",
    "target = 'answered_correctly'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:05:58.187734Z",
     "iopub.status.busy": "2020-12-28T12:05:58.187015Z",
     "iopub.status.idle": "2020-12-28T12:08:11.181687Z",
     "shell.execute_reply": "2020-12-28T12:08:11.181059Z"
    },
    "papermill": {
     "duration": 133.018906,
     "end_time": "2020-12-28T12:08:11.181874",
     "exception": false,
     "start_time": "2020-12-28T12:05:58.162968",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_df = dt.fread('../input/riiid-test-answer-prediction/train.csv', columns = set(data_types_dict.keys())).to_pandas()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:08:11.227654Z",
     "iopub.status.busy": "2020-12-28T12:08:11.226730Z",
     "iopub.status.idle": "2020-12-28T12:08:23.059595Z",
     "shell.execute_reply": "2020-12-28T12:08:23.060156Z"
    },
    "papermill": {
     "duration": 11.859375,
     "end_time": "2020-12-28T12:08:23.060335",
     "exception": false,
     "start_time": "2020-12-28T12:08:11.200960",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training dataset detailed information\n",
      "**************************************************\n",
      "Columns: Index(['timestamp', 'user_id', 'content_id', 'answered_correctly',\n",
      "       'prior_question_elapsed_time', 'prior_question_had_explanation'],\n",
      "      dtype='object')\n",
      "**************************************************\n",
      "Shape: (101230332, 6)\n",
      "**************************************************\n",
      "NA values in each column: 2744044\n",
      "**************************************************\n"
     ]
    }
   ],
   "source": [
    "print('Training dataset detailed information')\n",
    "print('*' * 50)\n",
    "print('Columns:', train_df.columns)\n",
    "print('*' * 50)\n",
    "print('Shape:', train_df.shape)\n",
    "print('*' * 50)\n",
    "print('NA values in each column:', sum(train_df.isna().sum()))\n",
    "print('*' * 50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:08:23.135933Z",
     "iopub.status.busy": "2020-12-28T12:08:23.135024Z",
     "iopub.status.idle": "2020-12-28T12:08:49.056583Z",
     "shell.execute_reply": "2020-12-28T12:08:49.055874Z"
    },
    "papermill": {
     "duration": 25.965956,
     "end_time": "2020-12-28T12:08:49.056688",
     "exception": false,
     "start_time": "2020-12-28T12:08:23.090732",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_df = train_df[train_df[target] != -1].reset_index(drop = True, inplace = False)#获取target非-1的样本\n",
    "\n",
    "train_df['prior_question_had_explanation'].fillna(False, inplace = True)#用False填充nan\n",
    "\n",
    "train_df = train_df.astype(data_types_dict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:08:49.099074Z",
     "iopub.status.busy": "2020-12-28T12:08:49.098400Z",
     "iopub.status.idle": "2020-12-28T12:08:49.102062Z",
     "shell.execute_reply": "2020-12-28T12:08:49.101640Z"
    },
    "papermill": {
     "duration": 0.025948,
     "end_time": "2020-12-28T12:08:49.102148",
     "exception": false,
     "start_time": "2020-12-28T12:08:49.076200",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "#train_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:08:49.149044Z",
     "iopub.status.busy": "2020-12-28T12:08:49.147924Z",
     "iopub.status.idle": "2020-12-28T12:09:04.575829Z",
     "shell.execute_reply": "2020-12-28T12:09:04.576432Z"
    },
    "papermill": {
     "duration": 15.455168,
     "end_time": "2020-12-28T12:09:04.576622",
     "exception": false,
     "start_time": "2020-12-28T12:08:49.121454",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_df['lag'] = train_df.groupby('user_id')[target].shift()\n",
    "\n",
    "cum = train_df.groupby('user_id')['lag'].agg(['cumsum', 'cumcount']) # 列方向上求累积和 和累计个数\n",
    "#  学习进步的增长率\n",
    "train_df['user_correctness'] = cum['cumsum'] / cum['cumcount']\n",
    "# \n",
    "train_df.drop(columns = ['lag'], inplace = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:04.659098Z",
     "iopub.status.busy": "2020-12-28T12:09:04.658229Z",
     "iopub.status.idle": "2020-12-28T12:09:11.114306Z",
     "shell.execute_reply": "2020-12-28T12:09:11.113809Z"
    },
    "papermill": {
     "duration": 6.501865,
     "end_time": "2020-12-28T12:09:11.114403",
     "exception": false,
     "start_time": "2020-12-28T12:09:04.612538",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Overall correctness of users 用户回答问题正确的比例，数目和次数 sum是回答正确的次数，count是回答的xx题目的总次数\n",
    "user_agg = train_df.groupby('user_id')[target].agg(['sum', 'count'])\n",
    "# Overall difficulty of questions每个content出现的次数和被回答正确的比例\n",
    "content_agg = train_df.groupby('content_id')[target].agg(['sum', 'count'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:11.201136Z",
     "iopub.status.busy": "2020-12-28T12:09:11.199962Z",
     "iopub.status.idle": "2020-12-28T12:09:17.470476Z",
     "shell.execute_reply": "2020-12-28T12:09:17.471694Z"
    },
    "papermill": {
     "duration": 6.296112,
     "end_time": "2020-12-28T12:09:17.471925",
     "exception": false,
     "start_time": "2020-12-28T12:09:11.175813",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Take only 24 last observations of each user\n",
    "train_df = train_df.groupby('user_id').tail(24).reset_index(drop = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:17.544820Z",
     "iopub.status.busy": "2020-12-28T12:09:17.543923Z",
     "iopub.status.idle": "2020-12-28T12:09:19.447027Z",
     "shell.execute_reply": "2020-12-28T12:09:19.446476Z"
    },
    "papermill": {
     "duration": 1.94202,
     "end_time": "2020-12-28T12:09:19.447126",
     "exception": false,
     "start_time": "2020-12-28T12:09:17.505106",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "questions_df = pd.read_csv(\n",
    "    '../input/riiid-test-answer-prediction/questions.csv', \n",
    "    usecols = [0, 3],\n",
    "    dtype = {'question_id': 'int16', 'part': 'int8'}\n",
    ")\n",
    "train_df = pd.merge(train_df, questions_df, left_on = 'content_id', right_on = 'question_id', how = 'left')\n",
    "train_df.drop(columns = ['question_id'], inplace = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:19.491760Z",
     "iopub.status.busy": "2020-12-28T12:09:19.490644Z",
     "iopub.status.idle": "2020-12-28T12:09:19.734134Z",
     "shell.execute_reply": "2020-12-28T12:09:19.733651Z"
    },
    "papermill": {
     "duration": 0.267641,
     "end_time": "2020-12-28T12:09:19.734233",
     "exception": false,
     "start_time": "2020-12-28T12:09:19.466592",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_df['content_count'] = train_df['content_id'].map(content_agg['count']).astype('int32')#某问题被回答的次数\n",
    "\n",
    "train_df['content_id'] = train_df['content_id'].map(content_agg['sum'] / content_agg['count'])#某问题被回答正确的比例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:19.779276Z",
     "iopub.status.busy": "2020-12-28T12:09:19.778059Z",
     "iopub.status.idle": "2020-12-28T12:09:20.145773Z",
     "shell.execute_reply": "2020-12-28T12:09:20.147052Z"
    },
    "papermill": {
     "duration": 0.393325,
     "end_time": "2020-12-28T12:09:20.147244",
     "exception": false,
     "start_time": "2020-12-28T12:09:19.753919",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_df.prior_question_had_explanation=train_df.prior_question_had_explanation.astype('int8')\n",
    "\n",
    "train_df['lag'] = train_df.groupby('user_id')['prior_question_had_explanation'].shift()#用户是否"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:20.206646Z",
     "iopub.status.busy": "2020-12-28T12:09:20.205782Z",
     "iopub.status.idle": "2020-12-28T12:09:22.255482Z",
     "shell.execute_reply": "2020-12-28T12:09:22.254925Z"
    },
    "papermill": {
     "duration": 2.076015,
     "end_time": "2020-12-28T12:09:22.255603",
     "exception": false,
     "start_time": "2020-12-28T12:09:20.179588",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "#train_df['lag'] = train_df.groupby('user_id')['prior_question_had_explanation'].shift()#用户是否看到上一个问题的答案，第一个题目为null。通常前几个都为false，因为那是测试。\n",
    "cum = train_df.groupby('user_id')['lag'].agg(['cumsum', 'cumcount'])#看上一题解释的总数和列数\n",
    "train_df['explanation_mean'] = cum['cumsum'] / cum['cumcount']#解释的平均\n",
    "train_df['explanation_cumsum'] = cum['cumsum'] \n",
    "\n",
    "train_df.drop(columns=['lag'], inplace=True)\n",
    "\n",
    "train_df['explanation_mean'].fillna(0, inplace=True)\n",
    "train_df['explanation_cumsum'].fillna(0, inplace=True)\n",
    "train_df.explanation_mean=train_df.explanation_mean.astype('float16')\n",
    "train_df.explanation_cumsum=train_df.explanation_cumsum.astype('int16')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:22.300631Z",
     "iopub.status.busy": "2020-12-28T12:09:22.299763Z",
     "iopub.status.idle": "2020-12-28T12:09:22.632480Z",
     "shell.execute_reply": "2020-12-28T12:09:22.631992Z"
    },
    "papermill": {
     "duration": 0.357491,
     "end_time": "2020-12-28T12:09:22.632597",
     "exception": false,
     "start_time": "2020-12-28T12:09:22.275106",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "explanation_agg = train_df.groupby('user_id')['prior_question_had_explanation'].agg(['sum', 'count'])#与上面cusum和cucount的区别\n",
    "explanation_agg = explanation_agg.astype('int16')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:22.766374Z",
     "iopub.status.busy": "2020-12-28T12:09:22.765473Z",
     "iopub.status.idle": "2020-12-28T12:09:24.208605Z",
     "shell.execute_reply": "2020-12-28T12:09:24.209758Z"
    },
    "papermill": {
     "duration": 1.557724,
     "end_time": "2020-12-28T12:09:24.209945",
     "exception": false,
     "start_time": "2020-12-28T12:09:22.652221",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "max_timestamp_u = train_df[['user_id','timestamp']].groupby(['user_id']).agg(['max']).reset_index()#取出timestamp的最大值\n",
    "max_timestamp_u.columns = ['user_id', 'max_time_stamp']#重新设置columns\n",
    "\n",
    "train_df['lagtime'] = train_df.groupby('user_id')['timestamp'].shift()\n",
    "train_df['lagtime']=train_df['timestamp']-train_df['lagtime']#此用户交互与该用户完成第一个事件之间的时间（毫秒）。\n",
    "train_df['lagtime'].fillna(0, inplace=True)#用0填充空值\n",
    "train_df.lagtime=train_df.lagtime.astype('int32')#数据格式转换\n",
    "\n",
    "lagtime_agg = train_df.groupby('user_id')['lagtime'].agg(['mean'])#完成每一题的平均时间\n",
    "train_df['lagtime_mean'] = train_df['user_id'].map(lagtime_agg['mean'])#map映射\n",
    "train_df.lagtime_mean=train_df.lagtime_mean.astype('int32')#转换数据格式\n",
    "\n",
    "\n",
    "train_df['timestamp']=train_df['timestamp']/(1000*3600)#时间转换为小时\n",
    "train_df.timestamp=train_df.timestamp.astype('int16')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "papermill": {
     "duration": 0.028519,
     "end_time": "2020-12-28T12:09:24.272121",
     "exception": false,
     "start_time": "2020-12-28T12:09:24.243602",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "提取验证集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:24.323580Z",
     "iopub.status.busy": "2020-12-28T12:09:24.322453Z",
     "iopub.status.idle": "2020-12-28T12:09:26.888896Z",
     "shell.execute_reply": "2020-12-28T12:09:26.890007Z"
    },
    "papermill": {
     "duration": 2.597034,
     "end_time": "2020-12-28T12:09:26.890184",
     "exception": false,
     "start_time": "2020-12-28T12:09:24.293150",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Ratio is 6/24 = 25%\n",
    "valid_df = train_df.groupby('user_id').tail(6)\n",
    "train_df.drop(valid_df.index, inplace = True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "papermill": {
     "duration": 0.041135,
     "end_time": "2020-12-28T12:09:27.011598",
     "exception": false,
     "start_time": "2020-12-28T12:09:26.970463",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:27.110253Z",
     "iopub.status.busy": "2020-12-28T12:09:27.108639Z",
     "iopub.status.idle": "2020-12-28T12:09:27.116377Z",
     "shell.execute_reply": "2020-12-28T12:09:27.117950Z"
    },
    "papermill": {
     "duration": 0.073221,
     "end_time": "2020-12-28T12:09:27.118193",
     "exception": false,
     "start_time": "2020-12-28T12:09:27.044972",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "\n",
    "features = [ 'timestamp','lagtime',#'lagtime_mean',\n",
    "    'content_id', 'prior_question_elapsed_time', \n",
    "            'prior_question_had_explanation', 'user_correctness', \n",
    "            'part', 'content_count','explanation_mean','explanation_cumsum']\n",
    "'''\n",
    "features = [ 'timestamp','lagtime','lagtime_mean',\n",
    "    'content_id', 'prior_question_elapsed_time', \n",
    "            'prior_question_had_explanation', 'user_correctness', \n",
    "            'part', 'content_count']'''\n",
    "cat_features = ['part']\n",
    "\n",
    "\n",
    "params = {\n",
    "    'loss_function': 'Logloss',\n",
    "    'eval_metric': 'AUC',\n",
    "    'task_type': 'GPU',\n",
    "    'grow_policy': 'Lossguide',\n",
    "    'iterations': 2500,\n",
    "    'learning_rate': 0.07,\n",
    "    'random_seed': 0,\n",
    "    'l2_leaf_reg': 1e-1,\n",
    "    'depth': 15,\n",
    "    'max_leaves': 10,\n",
    "    'border_count': 128,\n",
    "    'verbose': 100,\n",
    "    'cat_features':cat_features,\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:09:27.195899Z",
     "iopub.status.busy": "2020-12-28T12:09:27.195219Z",
     "iopub.status.idle": "2020-12-28T12:10:00.159350Z",
     "shell.execute_reply": "2020-12-28T12:10:00.160200Z"
    },
    "papermill": {
     "duration": 32.99845,
     "end_time": "2020-12-28T12:10:00.160354",
     "exception": false,
     "start_time": "2020-12-28T12:09:27.161904",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from catboost import CatBoostClassifier, Pool\n",
    "\n",
    "# Training and validating data\n",
    "train_set = Pool(train_df[features], label = train_df[target],cat_features = cat_features)\n",
    "val_set = Pool(valid_df[features], label = valid_df[target],cat_features = cat_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:10:00.230692Z",
     "iopub.status.busy": "2020-12-28T12:10:00.229833Z",
     "iopub.status.idle": "2020-12-28T12:15:12.885604Z",
     "shell.execute_reply": "2020-12-28T12:15:12.886447Z"
    },
    "papermill": {
     "duration": 312.693891,
     "end_time": "2020-12-28T12:15:12.886646",
     "exception": false,
     "start_time": "2020-12-28T12:10:00.192755",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0:\tlearn: 0.7303881\ttest: 0.7096431\tbest: 0.7096431 (0)\ttotal: 102ms\tremaining: 4m 15s\n",
      "100:\tlearn: 0.7550097\ttest: 0.7375029\tbest: 0.7375029 (100)\ttotal: 10.7s\tremaining: 4m 13s\n",
      "200:\tlearn: 0.7571999\ttest: 0.7400687\tbest: 0.7400687 (200)\ttotal: 21s\tremaining: 4m\n",
      "300:\tlearn: 0.7581694\ttest: 0.7409446\tbest: 0.7409446 (300)\ttotal: 31.1s\tremaining: 3m 47s\n",
      "400:\tlearn: 0.7587903\ttest: 0.7414724\tbest: 0.7414724 (400)\ttotal: 40.4s\tremaining: 3m 31s\n",
      "500:\tlearn: 0.7591971\ttest: 0.7417947\tbest: 0.7417947 (500)\ttotal: 49.6s\tremaining: 3m 18s\n",
      "600:\tlearn: 0.7595699\ttest: 0.7420488\tbest: 0.7420488 (600)\ttotal: 58.7s\tremaining: 3m 5s\n",
      "700:\tlearn: 0.7598254\ttest: 0.7422498\tbest: 0.7422498 (700)\ttotal: 1m 9s\tremaining: 2m 58s\n",
      "800:\tlearn: 0.7600787\ttest: 0.7424541\tbest: 0.7424613 (799)\ttotal: 1m 19s\tremaining: 2m 47s\n",
      "900:\tlearn: 0.7603100\ttest: 0.7426743\tbest: 0.7426743 (900)\ttotal: 1m 28s\tremaining: 2m 37s\n",
      "1000:\tlearn: 0.7605163\ttest: 0.7428354\tbest: 0.7428354 (1000)\ttotal: 1m 38s\tremaining: 2m 27s\n",
      "1100:\tlearn: 0.7606952\ttest: 0.7429505\tbest: 0.7429505 (1099)\ttotal: 1m 47s\tremaining: 2m 16s\n",
      "1200:\tlearn: 0.7608332\ttest: 0.7430432\tbest: 0.7430432 (1200)\ttotal: 1m 56s\tremaining: 2m 6s\n",
      "1300:\tlearn: 0.7609759\ttest: 0.7431292\tbest: 0.7431292 (1300)\ttotal: 2m 6s\tremaining: 1m 56s\n",
      "1400:\tlearn: 0.7610829\ttest: 0.7432092\tbest: 0.7432092 (1400)\ttotal: 2m 17s\tremaining: 1m 47s\n",
      "1500:\tlearn: 0.7612175\ttest: 0.7433169\tbest: 0.7433169 (1500)\ttotal: 2m 25s\tremaining: 1m 37s\n",
      "1600:\tlearn: 0.7613518\ttest: 0.7434092\tbest: 0.7434097 (1596)\ttotal: 2m 35s\tremaining: 1m 27s\n",
      "1700:\tlearn: 0.7614434\ttest: 0.7434612\tbest: 0.7434636 (1699)\ttotal: 2m 45s\tremaining: 1m 17s\n",
      "1800:\tlearn: 0.7615387\ttest: 0.7435474\tbest: 0.7435474 (1800)\ttotal: 2m 54s\tremaining: 1m 7s\n",
      "1900:\tlearn: 0.7616301\ttest: 0.7436010\tbest: 0.7436010 (1900)\ttotal: 3m 3s\tremaining: 57.8s\n",
      "2000:\tlearn: 0.7617142\ttest: 0.7436439\tbest: 0.7436441 (1999)\ttotal: 3m 13s\tremaining: 48.4s\n",
      "2100:\tlearn: 0.7617893\ttest: 0.7437013\tbest: 0.7437018 (2097)\ttotal: 3m 23s\tremaining: 38.7s\n",
      "2200:\tlearn: 0.7618677\ttest: 0.7437750\tbest: 0.7437753 (2199)\ttotal: 3m 32s\tremaining: 28.9s\n",
      "2300:\tlearn: 0.7619389\ttest: 0.7438219\tbest: 0.7438239 (2287)\ttotal: 3m 41s\tremaining: 19.2s\n",
      "2400:\tlearn: 0.7620084\ttest: 0.7438606\tbest: 0.7438606 (2400)\ttotal: 3m 50s\tremaining: 9.52s\n",
      "2499:\tlearn: 0.7620791\ttest: 0.7439106\tbest: 0.7439115 (2497)\ttotal: 4m\tremaining: 0us\n",
      "bestTest = 0.7439115345\n",
      "bestIteration = 2497\n",
      "Shrink model to first 2498 iterations.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<catboost.core.CatBoostClassifier at 0x7f74fc2e55d0>"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Model definition\n",
    "model = CatBoostClassifier(**params)\n",
    "\n",
    "# Fitting\n",
    "model.fit(train_set, eval_set = val_set, use_best_model = True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:15:13.110623Z",
     "iopub.status.busy": "2020-12-28T12:15:12.980443Z",
     "iopub.status.idle": "2020-12-28T12:15:20.726703Z",
     "shell.execute_reply": "2020-12-28T12:15:20.726262Z"
    },
    "papermill": {
     "duration": 7.798768,
     "end_time": "2020-12-28T12:15:20.726805",
     "exception": false,
     "start_time": "2020-12-28T12:15:12.928037",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['./1228_2_loan_model.pkl']"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import joblib\n",
    "# 模型存储\n",
    "joblib.dump(model, './1228_2_loan_model.pkl')\n",
    "# 模型加载\n",
    "#model = joblib.load('../input/loan_model.pkl')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "papermill": {
     "duration": 0.027143,
     "end_time": "2020-12-28T12:15:20.781974",
     "exception": false,
     "start_time": "2020-12-28T12:15:20.754831",
     "status": "completed"
    },
    "tags": []
   },
   "source": [
    "接口，这里是相比于国内的比赛有很大的不同。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:15:20.851245Z",
     "iopub.status.busy": "2020-12-28T12:15:20.850302Z",
     "iopub.status.idle": "2020-12-28T12:15:21.947308Z",
     "shell.execute_reply": "2020-12-28T12:15:21.946825Z"
    },
    "papermill": {
     "duration": 1.13747,
     "end_time": "2020-12-28T12:15:21.947407",
     "exception": false,
     "start_time": "2020-12-28T12:15:20.809937",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "user_sum_dict = user_agg['sum'].astype('int16').to_dict(defaultdict(int))\n",
    "user_count_dict = user_agg['count'].astype('int16').to_dict(defaultdict(int))\n",
    "content_sum_dict = content_agg['sum'].astype('int32').to_dict(defaultdict(int))\n",
    "content_count_dict = content_agg['count'].astype('int32').to_dict(defaultdict(int))\n",
    "\n",
    "explanation_sum_dict = explanation_agg['sum'].astype('int16').to_dict(defaultdict(int))\n",
    "explanation_count_dict = explanation_agg['count'].astype('int16').to_dict(defaultdict(int))\n",
    "\n",
    "\n",
    "lagtime_mean_dict = lagtime_agg['mean'].astype('int32').to_dict(defaultdict(int))\n",
    "max_timestamp_u_dict = max_timestamp_u.set_index('user_id').to_dict()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:15:22.012344Z",
     "iopub.status.busy": "2020-12-28T12:15:22.011829Z",
     "iopub.status.idle": "2020-12-28T12:15:22.016066Z",
     "shell.execute_reply": "2020-12-28T12:15:22.015618Z"
    },
    "papermill": {
     "duration": 0.039229,
     "end_time": "2020-12-28T12:15:22.016155",
     "exception": false,
     "start_time": "2020-12-28T12:15:21.976926",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    env = riiideducation.make_env()\n",
    "except:\n",
    "    pass\n",
    "iter_test = env.iter_test()\n",
    "prior_test_df = None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-12-28T12:15:22.122777Z",
     "iopub.status.busy": "2020-12-28T12:15:22.121875Z",
     "iopub.status.idle": "2020-12-28T12:15:22.775265Z",
     "shell.execute_reply": "2020-12-28T12:15:22.776260Z"
    },
    "papermill": {
     "duration": 0.732446,
     "end_time": "2020-12-28T12:15:22.776428",
     "exception": false,
     "start_time": "2020-12-28T12:15:22.043982",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "for (test_df, sample_prediction_df) in iter_test:\n",
    "    if prior_test_df is not None:\n",
    "        prior_test_df[target] = eval(test_df['prior_group_answers_correct'].iloc[0])\n",
    "        prior_test_df = prior_test_df[prior_test_df[target] != -1].reset_index(drop = True)\n",
    "        \n",
    "        user_ids = prior_test_df['user_id'].values\n",
    "        content_ids = prior_test_df['content_id'].values\n",
    "        targets = prior_test_df[target].values\n",
    "        \n",
    "        for user_id, content_id, answered_correctly in zip(user_ids, content_ids, targets):\n",
    "            user_sum_dict[user_id] += answered_correctly\n",
    "            user_count_dict[user_id] += 1\n",
    "            content_sum_dict[content_id] += answered_correctly\n",
    "            content_count_dict[content_id] += 1\n",
    "\n",
    "    prior_test_df = test_df.copy()\n",
    "    \n",
    "    test_df = test_df[test_df['content_type_id'] == 0].reset_index(drop = True)#测试数据\n",
    "    test_df = pd.merge(test_df, questions_df, left_on = 'content_id', right_on = 'question_id', how = 'left')\n",
    "    test_df['prior_question_had_explanation'] = test_df['prior_question_had_explanation'].fillna(False).astype('bool')    \n",
    "    \n",
    "    user_sum = np.zeros(len(test_df), dtype = np.int16)\n",
    "    user_count = np.zeros(len(test_df), dtype = np.int16)\n",
    "    content_sum = np.zeros(len(test_df), dtype = np.int32)\n",
    "    content_count = np.zeros(len(test_df), dtype = np.int32)\n",
    "    explanation_sum = np.zeros(len(test_df), dtype=np.int32)\n",
    "    explanation_count = np.zeros(len(test_df), dtype=np.int32)\n",
    "    \n",
    "    lagtime = np.zeros(len(test_df), dtype=np.int32)\n",
    "    lagtime_mean = np.zeros(len(test_df), dtype=np.int32)\n",
    "    \n",
    "    for i, (user_id, content_id,timestamp) in enumerate(zip(test_df['user_id'].values, test_df['content_id'].values,test_df['timestamp'].values)):\n",
    "        user_sum[i] = user_sum_dict[user_id]\n",
    "        user_count[i] = user_count_dict[user_id]\n",
    "        content_sum[i] = content_sum_dict[content_id]\n",
    "        content_count[i] = content_count_dict[content_id]\n",
    "        explanation_sum[i] = explanation_sum_dict[user_id]\n",
    "        explanation_count[i] = explanation_count_dict[user_id]\n",
    "        \n",
    "        if user_id in max_timestamp_u_dict['max_time_stamp'].keys():\n",
    "            lagtime[i] = timestamp-max_timestamp_u_dict['max_time_stamp'][user_id]\n",
    "            max_timestamp_u_dict['max_time_stamp'][user_id]=timestamp\n",
    "            lagtime_mean[i] = (lagtime_mean_dict[user_id]+lagtime[i])/2           \n",
    "        else:\n",
    "            lagtime[i]=0\n",
    "            max_timestamp_u_dict['max_time_stamp'].update({user_id:timestamp})\n",
    "            lagtime_mean_dict.update({user_id:timestamp})\n",
    "            lagtime_mean[i]=(lagtime_mean_dict[user_id]+lagtime[i])/2\n",
    "\n",
    "    test_df['user_correctness'] = user_sum / user_count\n",
    "    test_df['content_count'] = content_count\n",
    "    test_df['content_id'] = content_sum / content_count\n",
    "    test_df['explanation_mean'] = explanation_sum / explanation_count\n",
    "    test_df['explanation_cumsum'] = explanation_sum \n",
    "    test_df[\"lagtime\"] = lagtime\n",
    "    test_df[\"lagtime_mean\"] = lagtime_mean\n",
    "    test_df['timestamp']=test_df['timestamp']/(1000*3600)#时间转换为小时    \n",
    "\n",
    "       \n",
    "    test_df[target] = model.predict_proba(test_df[features])[:,1]\n",
    "    env.predict(test_df[['row_id', target]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "papermill": {
     "duration": 0.042077,
     "end_time": "2020-12-28T12:15:22.864277",
     "exception": false,
     "start_time": "2020-12-28T12:15:22.822200",
     "status": "completed"
    },
    "tags": []
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  },
  "papermill": {
   "duration": 599.84225,
   "end_time": "2020-12-28T12:15:23.922535",
   "environment_variables": {},
   "exception": null,
   "input_path": "__notebook__.ipynb",
   "output_path": "__notebook__.ipynb",
   "parameters": {},
   "start_time": "2020-12-28T12:05:24.080285",
   "version": "2.1.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
